#include "fixed64Helper.h"

bool write_fixedvalue_for_int(fixedByte* buf, int length, int& pos, int v)
{
	if (!buf || pos < 0 || pos + sizeof(int) > length)
		return false;

	int value = v;
	*(int*)(buf + pos) = value;

	pos += sizeof(int);

	return true;
}

bool write_fixedvalue_for_short(fixedByte* buf, int length, int& pos, short v)
{
	if (!buf || pos < 0 || pos + sizeof(short) > length)
		return false;

	*(short*)(buf + pos) = v;

	pos += sizeof(short);

	return true;
}

bool write_fixedvalue_for_float(fixedByte* buf, int length, int& pos, float v)
{
	if (!buf || pos < 0 || pos + sizeof(fixedLL) > length)
		return false;

	fixedLL value = (fixedLL)(v * 65536.0 + 0.5);
	*(fixedLL*)(buf + pos) = value;

	pos += sizeof(fixedLL);

	return true;
}

bool write_fixedvalue_for_double(fixedByte* buf, int length, int& pos, double v)
{
	if (!buf || pos < 0 || pos + sizeof(fixedLL) > length)
		return false;

	fixedLL value = (fixedLL)(v * 65536.0 + 0.5);

	*(fixedLL*)(buf + pos) = value;
	pos += sizeof(fixedLL);

	return true;
}

bool write_fixedvalue_for_v3(fixedByte* buf, int length, int& pos,const float* v)
{
	if (!write_fixedvalue_for_float(buf, length, pos, v[0]))
		return false;
	if (!write_fixedvalue_for_float(buf, length, pos, v[1]))
		return false;
	if (!write_fixedvalue_for_float(buf, length, pos, v[2]))
		return false;
	return true;
}

bool read_fixed64(fixedByte* buf, int length, int& pos, fixed64& v, bool swapEndian)
{
	if (!buf || pos < 0 || pos + sizeof(FPRaw) > length || sizeof(FPRaw) != 8)
		return false;

	if (swapEndian)
	{
		if (!swap_endian_for_fixed64(buf, length, pos))
			return false;
	}

	FPRaw fpv = *(FPRaw*)(buf + pos);
	pos += sizeof(FPRaw);
	v = fpv;

	return true;
}

bool read_fixed64_v3(fixedByte* buf, int length, int& pos, fixed64* v, bool swapEndian)
{
	if (!v)
		return false;
	if (!read_fixed64(buf, length, pos, v[0], swapEndian))
		return false;
	if (!read_fixed64(buf, length, pos, v[1], swapEndian))
		return false;
	if (!read_fixed64(buf, length, pos, v[2], swapEndian))
		return false;
	return true;
}

bool read_fixedvalue_for_int(fixedByte* buf, int length, int& pos, int& v, bool swapEndian)
{
	if (!buf || pos < 0 || pos + sizeof(int) > length || sizeof(int) != 4)
		return false;

	if (swapEndian)
	{
		if (!swap_endian_for_int(buf, length, pos))
			return false;
	}

	int fpv = *(int*)(buf + pos);
	pos += sizeof(int);
	v = fpv;

	return true;
}

bool read_fixedvalue_for_uint(fixedByte* buf, int length, int& pos, unsigned int& v, bool swapEndian)
{
	if (!buf || pos < 0 || pos + sizeof(unsigned int) > length || sizeof(unsigned int) != 4)
		return false;

	if (swapEndian)
	{
		if (!swap_endian_for_int(buf, length, pos))
			return false;
	}

	unsigned int fpv = *(unsigned int*)(buf + pos);
	pos += sizeof(unsigned int);
	v = fpv;

	return true;
}

bool read_fixedvalue_for_short(fixedByte* buf, int length, int& pos, unsigned short& v, bool swapEndian)
{
	if (!buf || pos < 0 || pos + sizeof(unsigned short) > length || sizeof(unsigned short) != 2)
		return false;

	if (swapEndian)
	{
		if (!swap_endian_for_int(buf, length, pos))
			return false;
	}

	v = *(unsigned short*)(buf + pos);
	pos += sizeof(unsigned short);

	return true;
}

bool swap_endian_for_short(void* buf, int length, int pos)
{
	int n = sizeof(short);
	if (n != 2)
		return false;
	if (!buf || pos < 0 || pos + n > length)
		return false;
	swap_byte((fixedByte*)buf + pos, (fixedByte*)buf + pos + 1);
	return true;
}

bool swap_endian_for_int(void* buf, int length, int pos)
{
	int n = sizeof(int);
	if (n != 4)
		return false;
	if (!buf || pos < 0 || pos + n > length)
		return false;
	swap_byte((fixedByte*)buf + pos, (fixedByte*)buf + pos + 3);
	swap_byte((fixedByte*)buf + pos + 1, (fixedByte*)buf + pos + 2);
	return true;
}

bool swap_endian_for_fixed64(void* buf, int length, int pos)
{
	int n = sizeof(FPRaw);
	if (n != 8)
		return false;
	int half = n >> 1;

	if (!buf || pos < 0 || pos + n > length)
		return false;

	for (int i = 0; i < half; ++i)
	{
		swap_byte((fixedByte*)buf + pos + i, (fixedByte*)buf + pos + n - 1 - i);
	}

	return true;
}

bool swap_endian_for_fixed64_v3(void* buf, int length, int pos)
{
	int n = sizeof(FPRaw);
	if (n != 8)
		return false;
	if (pos < 0 || pos + 24 > length)
		return false;
	if (!swap_endian_for_fixed64(buf, length, pos))
		return false;
	if (!swap_endian_for_fixed64(buf, length, pos + 8))
		return false;
	if (!swap_endian_for_fixed64(buf, length, pos + 16))
		return false;
	return true;
}
